package top.yehot.cmmu.spring.config;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import lombok.extern.slf4j.Slf4j;

/**
 * Spring异步线程池配置
 * 
 * @author lquan
 * @date 2022年4月6日 下午2:29:12
 */
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

	@Override
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		// 核心线程数
		executor.setCorePoolSize(10);
		// 最大线程数
        executor.setMaxPoolSize(100);
        // 队列大小
        executor.setQueueCapacity(100);
        // 线程池维护线程所允许的空闲时间
        executor.setKeepAliveSeconds(60);
        // 线程池中的线程的名称前缀
        executor.setThreadNamePrefix("Dflow-AsyncThread-");
        // 设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 设置线程池中任务的等待时间，如果超过这个时候还没有销毁就强制销毁，以确保应用最后能够被关闭，而不是阻塞住
        executor.setAwaitTerminationSeconds(60 * 20);
        /* 当pool已经达到max size的时候，如何处理新任务
         * CallerRunsPolicy: 会在execute 方法的调用线程中运行被拒绝的任务,如果执行程序已关闭，则会丢弃该任务
         * AbortPolicy: 抛出java.util.concurrent.RejectedExecutionException异常
         * DiscardOldestPolicy: 抛弃旧的任务
         * DiscardPolicy: 抛弃当前的任务
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize(); 
        return executor;
	}

	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return new AsyncExceptionHandler();
	}

	@Slf4j
	public static class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

		@Override
		public void handleUncaughtException(Throwable ex, Method method, Object... params) {
			log.error("[cmm-util-spring]-Spring-Async-Thread，method:{}, params:{}", method, params, ex);
		}
		
	}
}
